package edu.pku.sei.act.sampletask;

import edu.pku.sei.act.actools.ICapabilityManager;
import edu.pku.sei.act.actools.IEnvEntry;
import edu.pku.sei.act.actools.ITask;
import edu.pku.sei.act.actools.util.ACToolsNamingSpace;
import edu.pku.sei.act.actools.util.AbilityOutput;
import edu.pku.sei.act.actools.util.CapabilityMap;
import edu.pku.sei.act.actools.util.EnvInfo;
import edu.pku.sei.act.actools.util.Role;
import edu.pku.sei.act.actools.util.Task;
import edu.pku.sei.act.actools.util.TaskMessage;
import edu.pku.sei.act.sampletask.car._Car;
import edu.pku.sei.act.sampletask.parkinglot._Parkinglot;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class AutonomicParking extends Service {
	
	private static ICapabilityManager cm;
	private static IEnvEntry ee;
	private static Task task;
	private static String currentState;
	private static final String RECEIVER_INIT = "edu.pku.sei.act.sampletask.autonomicParkingReceiver";
	private static final String INIT_STATE = "init";
	private ServiceConnection CMConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName arg0, IBinder arg1) {
			
			cm = ICapabilityManager.Stub.asInterface(arg1);
		}

		public void onServiceDisconnected(ComponentName name) {
			
			cm = null;
		}
	};
	
	private ServiceConnection EEConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName arg0, IBinder arg1) {
			ee = IEnvEntry.Stub.asInterface(arg1);
			try {
				//ee.notifyLWrite(task.getDescriptor(), 0, -1);
				setState(INIT_STATE);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		public void onServiceDisconnected(ComponentName name) {
			ee = null;
		}
	};
	
	private  final ITask.Stub mbinder = new ITask.Stub() {
		
		public boolean playRole(String role) throws RemoteException {
			if(role.equals(_Car.ROLE_NAME)) {
				CapabilityMap map = new CapabilityMap();
				map.setTaskID(task.getTaskName()+"$"+_Car.ROLE_NAME);
				map.setTaskAbility(_Car.capability.START.getAbilityName());
				map.setType(_Car.capability.START.getType());
				map.setProviderID(ACToolsNamingSpace.ACToolsComponent.CAPABILITY_PROVIDER);//all same?
				map.setProviderAbility("start");//TODO why start?
				ee.LWrite(EnvInfo.HEAD_TUPLE + "," + map, 0, -1);
				
				map.setTaskAbility(_Car.capability.STOP.getAbilityName());
				map.setType(_Car.capability.STOP.getType());
				map.setProviderAbility("stop");
				ee.LWrite(EnvInfo.HEAD_TUPLE + "," + map, 0, -1);
				
				map.setTaskAbility(_Car.capability.GET_LOCATION.getAbilityName());
				map.setType(_Car.capability.GET_LOCATION.getType());
				map.setProviderAbility("getLocation");
				ee.LWrite(EnvInfo.HEAD_TUPLE + "," + map, 0, -1);
				
				map.setTaskAbility(_Car.capability.MARK_PARKING_SLOT.getAbilityName());
				map.setType(_Car.capability.MARK_PARKING_SLOT.getType());
				map.setProviderAbility("markPosition");
				ee.LWrite(EnvInfo.HEAD_TUPLE + "," + map, 0, -1);
				
				
				String s = cm.invokeCapability(_Car.capability._START, null);
				Log.v("@AutonomicParking!startOutput template",s);
				_Car.capability.START_OUTPUT = new AbilityOutput(s);
				String ss = cm.invokeCapability(_Car.capability._STOP, null);
				Log.v("@AutonomicParking!stopOutput template",ss);
				_Car.capability.STOP_OUTPUT = new AbilityOutput(ss);
				setState(_Car.state.PREPARE_TO_ENTER);
				
			} else if (role.equals(_Parkinglot.ROLE_NAME)){
				CapabilityMap map = new CapabilityMap();
				map.setTaskID(task.getTaskName()+"$"+_Parkinglot.ROLE_NAME);
				map.setTaskAbility(_Parkinglot.capability.PROVIDE_POSITION.getAbilityName());
				map.setType(_Parkinglot.capability.PROVIDE_POSITION.getType());
				map.setProviderID(ACToolsNamingSpace.ACToolsComponent.CAPABILITY_PROVIDER);
				map.setProviderAbility("providePosition");
				ee.LWrite(EnvInfo.HEAD_TUPLE+"," + map, 0, -1);
				setState(_Parkinglot.state.PREPARE);
			}
			return true;
		}
		
		public void interupt() throws RemoteException {
			
		}
		
		public String getTaskDescriptor() throws RemoteException {
			return task.getDescriptor();
		}
	};

	public void onCreate() {
		super.onCreate();
		
		task = new Task();
		task.setTaskName("AutonomicParking");
		
		
		final Intent serviceIntent1 = new Intent();
        serviceIntent1.setAction(ACToolsNamingSpace.ACToolsComponent.CAPABILITY_MANAGER);
        bindService(serviceIntent1,CMConnection,Context.BIND_AUTO_CREATE);
        
        final Intent serviceIntent2 = new Intent();
        serviceIntent2.setAction(ACToolsNamingSpace.ACToolsComponent.ENV_ENTRY);
        bindService(serviceIntent2,EEConnection,Context.BIND_AUTO_CREATE);
        
	}
	

	@Override
	public void onDestroy() {
		unbindService(CMConnection);
		unbindService(EEConnection);
		super.onDestroy();
	}


	@Override
	public IBinder onBind(Intent intent) {
		return mbinder;
	}

	public static Task getTask() {
		return task;
	}

	public static ICapabilityManager getCm() {
		return cm;
	}

	public static IEnvEntry getEe() {
		return ee;
	}
	
	public static void setState(String state) throws RemoteException {
		Log.v("@AutonomicParking  STATE:",state);
		currentState = state;
		TaskMessage msg = new TaskMessage();
		msg.setTaskName(task.getTaskName());
		ee.LTakeMany(EnvInfo.HEAD_READ_TEMPLATE + "," + msg);
		ee.LTakeMany(EnvInfo.HEAD_TAKE_TEMPLATE + "," + msg);
		//TODO RTake?
		//ee.RTakeMany(EnvInfo.HEAD_READ_TEMPLATE + "," + msg);
		//ee.RTakeMany(EnvInfo.HEAD_TAKE_TEMPLATE + "," + msg);
		
		ee.LTake(EnvInfo.HEAD_TAKE_TEMPLATE + "," + _Car.capability.START_OUTPUT);
		ee.LTake(EnvInfo.HEAD_TAKE_TEMPLATE + "," + _Car.capability.STOP_OUTPUT);
		
		if(state.equals(INIT_STATE)) {
			msg.setTopic(ACToolsNamingSpace.EnvInfo.PLAY_ROLE);
			ee.notifyLWrite(EnvInfo.HEAD_TAKE_TEMPLATE+ "$" + RECEIVER_INIT + "," + msg,0,-1);
		}
		else if(state.equals(_Car.state.PREPARE_TO_ENTER)){
			ee.LWrite(EnvInfo.HEAD_TAKE_TEMPLATE + "$" + _Car.transformation.STARTING + "," + _Car.capability.START_OUTPUT, 0, -1);
			ee.LWrite(EnvInfo.HEAD_TAKE_TEMPLATE + "$" + _Car.transformation.PARKING + "," + _Car.capability.STOP_OUTPUT, 0, -1);
		}
		else if(state.equals(_Car.state.DRIVING)) {
			ee.LWrite(EnvInfo.HEAD_TAKE_TEMPLATE + "$" + _Car.transformation.PARKING + "," + _Car.capability.STOP_OUTPUT, 0, -1);
		}
		else if(state.equals(_Car.state.QUERYING_PARKING_SLOT)) {
			msg = _Car.communication.PARKING_SLOT_NOTIFICATION.clone();
			msg.setReceiver(ee.getIdentity());
			long time = System.currentTimeMillis();
			ee.RWrite(EnvInfo.HEAD_TAKE_TEMPLATE + "$" + _Car.transformation.MARK_PARKING_SLOT + "," + msg, time , time + 2500);
			
			ee.notifyLWrite(EnvInfo.HEAD_READ_TEMPLATE + "$" + _Car.transformation.WAITING_FOR_RESPONSE + "," + new CapabilityMap(), 0, 0);
		}
		else if(state.equals(_Car.state.STOPPED)) {
			ee.LWrite(EnvInfo.HEAD_TAKE_TEMPLATE + "$" + _Car.transformation.STARTING + "," + _Car.capability.START_OUTPUT, 0, -1);
		} else
		//parkinglot state
		if (state.equals(_Parkinglot.state.READY)){
			msg = _Parkinglot.communication.PARKING_NOTIFICATION;
			ee.notifyRWrite(EnvInfo.HEAD_TAKE_TEMPLATE + '$' + _Parkinglot.transformation.WORKING
					+ "," + msg , 0, -1);
		} else if (state.equals(_Parkinglot.state.PREPARE)){
			ee.notifyLWrite(EnvInfo.HEAD_READ_TEMPLATE + "$" + _Parkinglot.transformation.PREPARING + "," + new CapabilityMap() , 0, -1);
		}
	}

	public static String getCurrentState() {
		return currentState;
	}

}
